#ifndef STUN_H
#define STUN_H
#ifdef __cplusplus
extern  "C"
{
#endif  /* end of #ifdef __cplusplus */

#include "xsapi.h"


#define STUN_VERSION 1.0

/* These macros should be calculated by the preprocessor and are used
   with compile-time constants only (so that there is no little-endian
   overhead at runtime). */
#define htons(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define ntohs(x) htons(x)
#define htonl(x) ((((x) & 0xff) << 24) | \
                     (((x) & 0xff00) << 8) | \
                     (((x) & 0xff0000UL) >> 8) | \
                     (((x) & 0xff000000UL) >> 24))
#define ntohl(x) htonl(x)

#define	_FALSE     0
#define	_TRUE      1

#define	TYR_TIMES	 										3
#define STUN_MAX_STRING 							256
#define STUN_MAX_UNKNOWN_ATTRIBUTES 	8
#define IP_BUFF_LEN										20
#define NAT_TYPE_BUFF_LEN							16

#define PORT 3478

#define REQ_LEN		28
#define RES_LEN		100

typedef unsigned char  UInt8;
typedef unsigned short UInt16;
typedef unsigned int   UInt32;
typedef struct{unsigned char octet[16];} UInt128;

//define types of stun message
#define BindingRequest            0x0001
#define BindingResponse           0x0101
#define BindingErrorResponse      0x0111
#define SharedSecretRequest       0x0002
#define SharedSecretResponse      0x0102
#define SharedSecretErrorResponse 0x0112
//define stun attributes
#define MappedAddress             0x0001
#define ResponseAddress           0x0002
#define ChangeRequest             0x0003
#define SourceAddress             0x0004
#define ChangedAddress            0x0005
#define Username                  0x0006
#define Password                  0x0007
#define MessageIntegrity          0x0008
#define ErrorCode                 0x0009
#define UnknowAttributes          0x000a
#define ReflectedFrom             0x000b

//define state here
#define Build             1
#define WaitResponse      2
#define ParseResponse     3
#define EndProcess        0
#define TIMEOUT		2000

typedef struct 
{
	UInt8	acMappedAddress[IP_BUFF_LEN];
	UInt8	acSourceAddress[IP_BUFF_LEN];
	UInt8	acChangedAddress[IP_BUFF_LEN];
	UInt8  cNatType ;
	UInt32  iHexMapip;
	UInt32 	iMappePort;
	UInt32 	iSourcePort;
	UInt32 	iChangePort;
}StunAddressInfo;


typedef struct
{
	UInt32 mapped_ip;
	UInt16 mapped_port;
	UInt32 changed_ip;
	UInt16 changed_port;
}Address4;

//define the head of stun message 
typedef struct 
{
	UInt16 msgType;
	UInt16 msgLength;
	UInt128 id;
}StunMsgHdr;


typedef struct
{
	UInt16 type;
	UInt16 length;
}StunAtrHdr;

typedef struct
{
	UInt16 port;
	UInt32 addr;
}StunAddress4;

typedef struct
{
	UInt8 pad;
	UInt8 family;
	StunAddress4 ipv4;
}StunAtrAddress4;

typedef struct
{
	UInt32 value;
}StunAtrChangeRequest;

typedef struct
{
	UInt16 pad; // all 0
	UInt8 errorClass;
	UInt8 number;
	char reason[STUN_MAX_STRING];
	UInt16 sizeReason;
}StunAtrError;

typedef struct
{
	UInt16 attrType[STUN_MAX_UNKNOWN_ATTRIBUTES];
	UInt16 numAttributes;
}StunAtrUnknown;

typedef struct
{
	char value[STUN_MAX_STRING];      
	UInt16 sizeValue;
}StunAtrString;

typedef struct
{
	char hash[20];
}StunAtrIntegrity;

typedef struct
{
	StunMsgHdr msgHdr;
	
	int hasMappedAddress;
	StunAtrAddress4  mappedAddress;
	
	int hasResponseAddress;
	StunAtrAddress4  responseAddress;
	
	int hasChangeRequest;
	StunAtrChangeRequest changeRequest;
	
	int hasSourceAddress;
	StunAtrAddress4 sourceAddress;
	
	int hasChangedAddress;
	StunAtrAddress4 changedAddress;
	
	int hasUsername;
	StunAtrString username;
	
	int hasPassword;
	StunAtrString password;
	
	int hasMessageIntegrity;
	StunAtrIntegrity messageIntegrity;
	
	int hasErrorCode;
	StunAtrError errorCode;
	
	int hasUnknownAttributes;
	StunAtrUnknown unknownAttributes;
	
	int hasReflectedFrom;
	StunAtrAddress4 reflectedFrom;
}StunMessage; 
//generat transction ID
UInt128 createTransctionID(void);

void buildSimBindingRequest(unsigned char *buf, UInt128 *ID);

void buildTestBindingRequest(unsigned char *buf, int change_ip, int change_port,
                              UInt128 *ID);

int sendBindingRequest(xsCtx_t *pstCtx, unsigned char *buf, UInt16 len, UInt32 ip, UInt16 port);

int receiveResponse(xsCtx_t *pstCtx, unsigned char *buf, UInt16 len);

int parseBindingResponse(unsigned char *buf, Address4 *addr, StunAddressInfo *stAddressinfo, UInt128 *ID, int count);

int GetMapAddr(xsCtx_t *pstCtx, StunAddressInfo *pstAddressinfo, unsigned int local_ip, unsigned int dst_ip, unsigned short dst_p);

#ifdef __cplusplus
}
#endif  /* end of #ifdef __cplusplus */

#endif
